package com.gvsoft.communication.server;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.gvsoft.communication.console.IControl;
import com.gvsoft.communication.console.Console;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.util.Map;
import java.util.Properties;
import java.util.StringTokenizer;
import java.util.concurrent.ConcurrentHashMap;


/**
 * Created with IntelliJ IDEA.
 * ProjectName:gvMsgRouting
 * Author: zhaoqiubo
 * Date: 15/8/5
 * Time: 上午8:34
 * Desc: 配置中心，初始化所有配置，保存系统常量及缓冲池
 * <p/>
 * 【一些约定】：
 * |-------------------------------------------
 * | 1、所有接收到的消息，称之为报文（Packet）
 * | 2、所有发出去的消息，称之为指令（Order）
 * |-------------------------------------------
 */
public class ServerConfig {

    //服务绑定的端口
    private Integer port;
    //服务器IP地址
    private String ip;
    /**
     * 报文区间分隔符，报文分为三个区间，HEADER区间、RID区间、BODY区间；
     * HEADER标记报文分类，RID为报文对象id，在一定周期内唯一；BODY为报文的内容区域。
     */
    public static String HBREGEX = "|";
    /**
     * 存储所有报文处理类的实例，一次性初始化进入Map（为连接通道（GVServer中使用）准备的单例类Map）
     */
    protected static Map<String, Object> PACKET_HANDLE_CLASS_MAP = new ConcurrentHashMap<String,Object>();
    /**
     * 配置报文处理类分类的外部分隔符，分隔符两边代表某一类报文处理类的属性描述。
     * 例如：R:com.gvsoft.server.model.RegisterHandleModel|E:com.gvsoft.server.model.ErrorHandleModel
     */
    private final String separatorOuter = "|";
    /**
     * 配置报文处理类分类的内部部分隔符,分割某一类报文处理类的header和body。
     * 例如：R:com.gvsoft.server.model.RegisterHandleModel
     */
    private final String separatorInner = ":";
    /*
    连接的超时时间
     */
    public Integer cleanThreadOutTime;
    /**
     * 连接清理线程的执行周期
     */
    public Integer cleanThreadCycle;

    /**
     * 网络报文读取缓冲区大小
     */
    private static Integer readBlock = 8192;
    /**
     * 指令写入缓冲区大小
     */
    private static Integer writeBlock = 8192;

    /**
     * 读缓冲池大小
     */
    private static Integer readBufferPoolSize = 1000;

    /**
     * 写缓冲池大小
     */
    private static Integer writeBufferPoolSize = 1000;

    /**
     * 默认listener数量
     */
    private static Integer listenerCount = 1;

    /**
     * 写入通道队列默认大小
     */
    private static Integer writeQueueSize = 1000;

    /**
     * 读处理线程池默认大小
     */
    private static Integer readHandleThreadCount = 10;

    private static Logger logger = LogManager.getLogger("server");

    //定义包头的字节大小
    public final static int PACKET_HEAD_LENGTH = 8;

    public ServerConfig(String config) {
        initConfig(config);
    }

    public final static String BUSI_TAG ="M";//业务包标记

    private int consolePort = 9090;

    /**
     * 初始化所有配置，包括ip、port、连接超时时间、清理连接周期，初始化单例处理类的两个缓冲池
     * @param config
     */
    private void initConfig(String config) {
        Properties p = new Properties();
        try {
            InputStreamReader reader = new InputStreamReader(new FileInputStream
                    (config), "utf-8");
            p.load(reader);
            this.ip = p.getProperty("server_ip");
            this.port = Integer.parseInt(p.getProperty("server_port").trim());
            this.cleanThreadOutTime = Integer.parseInt(p.getProperty("timeout_seconds").trim());
            this.cleanThreadCycle = Integer.parseInt(p.getProperty("clean_thread_cycle").trim());
            this.readBlock = Integer.parseInt(p.getProperty("read_block").trim());
            this.writeBlock = Integer.parseInt(p.getProperty("write_block").trim());
            this.readBufferPoolSize = Integer.parseInt(p.getProperty("read_buffer_pool_size").trim());
            this.writeBufferPoolSize = Integer.parseInt(p.getProperty("write_buffer_pool_size").trim());
            this.writeQueueSize = Integer.parseInt(p.getProperty("write_queue_size").trim());
            this.listenerCount = Integer.parseInt(p.getProperty("listener_count").trim());
            this.readHandleThreadCount = Integer.parseInt(p.getProperty("readhandle_thread_count").trim());
            this.consolePort = Integer.parseInt(p.getProperty("console_port").trim());

            initPacketHandleMap(p.getProperty("packet_handle_class"));
            initController(p.getProperty("console_class"));

            //处理json转化中的null问题，将对象的null属性包含在json的转化过程中。
            JSON.DEFAULT_GENERATE_FEATURE |= SerializerFeature.WriteMapNullValue.getMask();
            JSON.DEFAULT_GENERATE_FEATURE |= SerializerFeature.WriteNullStringAsEmpty.getMask();

            logger.info("GVServer消息路由服务配置初始化完成！");
            logger.info("————————————————————————————————————————————————————————————————————————");
            logger.info("|【特别鸣谢】：有理想的鱼、少帮主、旅客列车、任我飞、宋阳、砒霜大力丸、凌云、小胖！|");
            logger.info("————————————————————————————————————————————————————————————————————————");

        } catch (Exception e) {
            logger.info("Failed to initialize the configuration parameter！reason:"+e.getMessage());
        }
    }

    /**
     * 初始化报文实例池
     * @param handleCfgStr
     */
    private void initPacketHandleMap(String handleCfgStr) {
        String[] handleOuterArray = str2ArrayByChar(handleCfgStr, separatorOuter);
        try {
            for (int i = 0; i < handleOuterArray.length; i++) {
                String[] handleInnerArray = str2ArrayByChar(handleOuterArray[i], separatorInner);
                Class c = Class.forName(handleInnerArray[1]);
                Object handleClass = c.newInstance();
                ServerConfig.PACKET_HANDLE_CLASS_MAP.put(handleInnerArray[0], handleClass);
            }
        } catch (Exception e) {
            logger.error("Failed to initialize the PacketHandle model! reason:"+e.getMessage());
            e.printStackTrace();
        }
    }

    public int getConsolePort() {
        return consolePort;
    }

    public void setConsolePort(int consolePort) {
        this.consolePort = consolePort;
    }

    /**
     * 初始化报文实例池
     * @param consoleStr
     */
    private void initController(String consoleStr) {
        String[] handleOuterArray = str2ArrayByChar(consoleStr, separatorOuter);
        try {
            for (int i = 0; i < handleOuterArray.length; i++) {
                String[] handleInnerArray = str2ArrayByChar(handleOuterArray[i], separatorInner);
                Class c = Class.forName(handleInnerArray[1]);
                Object controllerClass = c.newInstance();
                Console.regCmd(handleInnerArray[0],(IControl) controllerClass);
            }
        } catch (Exception e) {
            logger.error("Failed to initialize the Controller! reason:"+e.getMessage());
            e.printStackTrace();
        }
    }
    /**
     * 从报文实例池中取出操作实例
     *
     * @param classKey
     * @return
     */
    public static Object getPacketHandleInstance(String classKey) {
        return ServerConfig.PACKET_HANDLE_CLASS_MAP.get(classKey);
    }

    /**
     *     根据分隔符，将字符串分割为数组
     * @param string
     * @param divisionChar
     * @return
     */
    private String[] str2ArrayByChar(String string, String divisionChar) {
        int i = 0;
        StringTokenizer tokenizer = new StringTokenizer(string, divisionChar);

        String[] str = new String[tokenizer.countTokens()];

        while (tokenizer.hasMoreTokens()) {
            str[i] = new String();
            str[i] = tokenizer.nextToken();
            i++;
        }

        return str;
    }

    public Integer getPort() {
        return port;
    }

    public String getIp() {
        return ip;
    }

    public Integer getCleanThreadOutTime() {
        return cleanThreadOutTime;
    }

    public Integer getCleanThreadCycle() {
        return cleanThreadCycle;
    }

    public static Integer getReadBlock() {
        return readBlock;
    }

    public static Integer getWriteBlock() {
        return writeBlock;
    }

    public static Integer getWriteBufferPoolSize() {
        return writeBufferPoolSize;
    }

    public static Integer getReadBufferPoolSize() {
        return readBufferPoolSize;
    }

    public  static Integer getListenerCount() {
        return listenerCount;
    }

    public static Integer getWriteQueueSize() {
        return writeQueueSize;
    }

    public static Integer getReadHandleThreadCount() {
        return readHandleThreadCount;
    }


}
